using System;
using System.Linq.Expressions;
using WindowsPhoneMVC.ActionResults;
using WindowsPhoneMVC.Navigation;

namespace WindowsPhoneMVC
{
    public class Controller
    {
        private static NavigationContext navigationContext;

        public NavigationContext NavigationContext
        {
            get { return navigationContext; }
        }

        public void Initialise(NavigationContext context)
        {
            navigationContext = context;
        }

        protected RefreshCurrentViewResult RefreshCurrentView()
        {
            return new RefreshCurrentViewResult(navigationContext);
        }

        protected DoNothingResult Nothing()
        {
            return new DoNothingResult(navigationContext);
        }

        protected BackResult Back()
        {
            return new BackResult(navigationContext);
        }

        /// <summary>
        /// Navigates back until the first matching Controller and Action. 
        /// You can use this to go all the way back to main, no matter how many navigations
        /// </summary>
        /// <typeparam name="TController"></typeparam>
        /// <param name="actionName"></param>
        /// <returns></returns>
        protected BackToResult BackTo<TController>(string actionName) where TController : Controller
        {
            var controllerName = typeof(TController).Name;
            return new BackToResult(navigationContext, controllerName, actionName);
        }

        protected RedirectResult RedirectTo(string controllerName, string actionName, params object[] parameters)
        {
            return new RedirectResult(
                navigationContext,
                () => navigationContext.Navigator.Invoke(controllerName, actionName, parameters));
        }

        protected RedirectResult RedirectTo<TController>(string actionName, params object[] parameters) where TController : Controller
        {
            return new RedirectResult(
                navigationContext,
                ()=> new ControllerActions<TController>(navigationContext.Navigator)
                    .Invoke(actionName, parameters));
        }

        protected RedirectResult RedirectTo<TController>(Expression<Func<TController, ActionResult>> actionSelector) where TController : Controller
        {
            return new RedirectResult(
                navigationContext,
                () => new ControllerActions<TController>(navigationContext.Navigator)
                    .Invoke(actionSelector));
        }

        /// <summary>
        /// Returns the passed result to the caller of InvokeWithResult
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="result"></param>
        /// <returns></returns>
        protected DataResult Result<T>(T result)
        {
            return new DataResult(navigationContext, result);
        }

        protected PageResult Page(string name, object model)
        {
            return new PageResult(name, model, navigationContext);
        }

        protected PageResult Page(string name)
        {
            return new PageResult(name, null, navigationContext);
        }

        protected PageResult Page(object model)
        {
            return new PageResult(navigationContext.Request.ActionName, model, navigationContext);
        }

        protected PageResult Page()
        {
            return new PageResult(navigationContext.Request.ActionName, null, navigationContext);
        }

        protected PartialViewResult Partial(object model)
        {
            return new PartialViewResult(navigationContext.Request.ActionName, model, navigationContext);
        }

        protected PartialViewResult Partial()
        {
            return new PartialViewResult(navigationContext.Request.ActionName, null, navigationContext);
        }

        protected void LoadingMessage(string loadingMessage)
        {
            var frame = navigationContext.Navigator.NavigationFrame;
            WindowsPhoneEssentials.Threading.Execute.OnUIThread(() => frame.LoadingMessage = loadingMessage);
        }
    }
}